package awk.etl.function.register;

import awk.etl.function.EtlFunction;
import awk.etl.function.EtlFunctionAnnotation;
import awk.etl.model.FunctionBean;
import cn.hutool.core.util.ClassUtil;
import com.google.common.collect.HashBasedTable;
import com.google.common.collect.Table;

import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * 基于继承信息获取所有的 namespace和其下的 function
 */
public class FunctionRegister {

    /**
     * nameSpace:functionName:FunctionBean
     */
    public static Table<String, String, FunctionBean> nameSpaceAndFunction= HashBasedTable.create();

    static {
        Set<Class<?>> instances = getInstances(EtlFunction.class);
        for (Class<?> instance : instances) {
            try {
                EtlFunction etlFunction = (EtlFunction)instance.newInstance();
                String namespace = etlFunction.nameSpace();

                // 取得方法
                Method[] methods = instance.getDeclaredMethods();
                for (Method method : methods) {
                    if (method.isAnnotationPresent(EtlFunctionAnnotation.class)){
                        ////TODO 获取所有 EtlFunction 的实现类，该实现类下的每一个方法都是内置函数（需要考虑工具方法的影响，所以最好使用注解方式）
                        String methodName = method.getName();
                        //函数访问修饰符 public protected private
                        String modifiers = Modifier.toString(method.getModifiers());
                        FunctionBean functionBean = FunctionBean.builder().namespace(namespace).functionName(methodName)
                                .functionClazz(instance).instance(etlFunction)
                                .method(method).build();
                        nameSpaceAndFunction.put(namespace,methodName,functionBean);
                    }
                }
            } catch (InstantiationException | IllegalAccessException e) {
                throw new RuntimeException(e);
            }
        }
    }



    /**
     * 非spring环境获取某个接口的所有实现类
     * @param supClass
     * @return
     */
    private static Set<Class<?>> getInstances(Class supClass) {
        String aPackage = ClassUtil.getPackage(supClass);
        Set<Class<?>> classes = ClassUtil.scanPackage(aPackage);
        Set<Class<?>> collect = classes.stream().filter(sonClass -> {
            boolean allAssignableFrom = ClassUtil.isAllAssignableFrom(new Class[]{supClass},
                    new Class[]{sonClass});
            //要将 本身排除
            return allAssignableFrom && sonClass != supClass;
        }).collect(Collectors.toSet());
        return collect;
    }
}
